﻿/**************************************************************
 *
 * 唯一标识：81ec85b5-986d-4832-b0b3-ce902543d3b1
 * 命名空间：Sgr.Trackers
 * 创建时间：2024/7/20 17:35:37
 * 机器名称：DESKTOP-HJ4OAG9
 * 创建者：CocoYuan
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Sgr.Caching.Services;
using Sgr.Generator;
using Sgr.Redis;
using Microsoft.Extensions.Logging;
using Sgr.DistributedLock;
using Sgr.Exceptions;
using StackExchange.Redis;

namespace Sgr.Trackers
{
    public class MessageTokenByRedis : IMessageToken
    {
        private readonly IRedisDatabaseContext _redisDatabaseContext;
        private readonly IStringIdGenerator _stringIdGenerator;
        private readonly ILogger _logger;

        private const string LOCK_VALUE = "MessageToken";

        public MessageTokenByRedis(IStringIdGenerator stringIdGenerator,
            IRedisDatabaseContext redisDatabaseContext,
            ILogger<RedisDistributedLock> logger)
        {
            _stringIdGenerator = stringIdGenerator;
            _redisDatabaseContext = redisDatabaseContext;
            _logger = logger;
        }

        /// <summary>
        /// 颁发令牌
        /// </summary>
        /// <param name="effectiveSecond">有效期，单位秒（默认1天）</param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<string> IssuingTokenAsync(int effectiveSecond = 86400, CancellationToken token = default)
        {
            var redisDatabase = await _redisDatabaseContext.ConnectAsync();
            if (redisDatabase == null)
            {
                _logger.LogError("颁发令牌失败,无法获取Redis连接!");
                return string.Empty;
            }

            string key = _stringIdGenerator.GenerateUniqueId();
            try
            {
                if (!await redisDatabase.LockTakeAsync(getKey(key), LOCK_VALUE, TimeSpan.FromSeconds(effectiveSecond)))
                    key = string.Empty;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "颁发令牌失败,调用 LockTakeAsync 异常！");
                _redisDatabaseContext.OnRedisError(ex, redisDatabase);

                key = string.Empty;
            }

            return key;
        }

        /// <summary>
        /// 验证令牌(原子操作)
        /// </summary>
        /// <param name="key"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<bool> VerifyTokenAsync(string key, CancellationToken token = default)
        {
            var redisDatabase = await _redisDatabaseContext.ConnectAsync();
            bool result = false;
            try
            {
                result = await redisDatabase.LockReleaseAsync(getKey(key), LOCK_VALUE);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "验证令牌失败,调用 LockReleaseAsync 异常！");
                _redisDatabaseContext.OnRedisError(ex, redisDatabase);
            }

            return result;
        }

        private RedisKey getKey(string key)
        {
            return _redisDatabaseContext.InstancePrefix.Append(".m.token.").Append(key);
        }
    }
}